package com.ruoyi.locksApi.service.impl;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.lock.domain.ACell;
import com.ruoyi.lock.domain.ATenantkey;
import com.ruoyi.lock.domain.ATenantuser;
import com.ruoyi.lock.domain.AWaringInfo;
import com.ruoyi.lock.mapper.*;
import com.ruoyi.locksApi.domain.dto.PhoneLoginDTO;
import com.ruoyi.locksApi.service.PhoneLoginService;
import com.ruoyi.system.mapper.SysNoticeMapper;
import com.ruoyi.tengxun.service.ISmsService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class PhoneLoginServiceImpl implements PhoneLoginService {

    private static final Logger log = LoggerFactory.getLogger(PhoneLoginServiceImpl.class);

    @Autowired
    private ATenantuserMapper tenantuserMapper;
    
    @Autowired
    private ADeviceMapper deviceMapper;
    
    @Autowired
    private ATenantkeyMapper tenantkeyMapper;
    
    @Autowired
    private AWaringInfoMapper waringInfoMapper;

    @Autowired
    private RedisCache redisCache;

    @Autowired
    private SysNoticeMapper sysNoticeMapper;
    
    @Autowired
    private ACellMapper aCellMapper;

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private ISmsService iSmsService;

    private static final String REDIS_API_KEY_PREFIX = "api:auth:";
    private static final long TOKEN_EXPIRE_DAYS = 30;
    private static final String SMS_CODE_KEY_PREFIX = "sms:code:";
    private static final int CODE_EXPIRE_MINUTES = 30;

    @Override
    public AjaxResult phoneLogin(PhoneLoginDTO loginDTO) {
        if (loginDTO == null || StringUtils.isEmpty(loginDTO.getPhone())) {
            return AjaxResult.error("手机号不能为空");
        }

        // TODO: 验证码校验逻辑
        if (StringUtils.isEmpty(loginDTO.getCode())) {
            return AjaxResult.error("验证码不能为空");
        }

        // 根据手机号查询用户
        ATenantuser user = tenantuserMapper.selectATenantuserByPhone(loginDTO.getPhone());
        if (user == null) {
            return AjaxResult.error("该手机号未注册，请先注册");
        }

        // 生成token
        String token = UUID.randomUUID().toString().replace("-", "");
        String redisKey = REDIS_API_KEY_PREFIX + token;

        // 构建返回数据
        Map<String, Object> result = new HashMap<>();
        result.put("token", token);
        result.put("userId", user.getId());
        result.put("name", user.getName());
        result.put("cellId", user.getCellId());
        result.put("phone", user.getPhone());
        result.put("type", user.getType());
        result.put("homeId", user.getHomeId());
        result.put("cellName", user.getCellName());
        result.put("unitName", user.getUnitName());
        result.put("floorName", user.getFloorName());
        result.put("roomName", user.getRoomName());

        // 将用户信息存入Redis，设置30天过期
        redisCache.setCacheObject(redisKey, result, (int)TOKEN_EXPIRE_DAYS, TimeUnit.DAYS);

        return AjaxResult.success("登录成功", result);
    }

    @Override
    public AjaxResult getDeviceInfo(Long homeId) {
        if (homeId == null) {
            return AjaxResult.error("房间ID不能为空");
        }
        
        Map<String, Object> deviceInfo = deviceMapper.selectDeviceByHomeId(homeId);
        if (deviceInfo == null || deviceInfo.isEmpty()) {
            return AjaxResult.error("未找到设备信息");
        }
        
        return AjaxResult.success(deviceInfo);
    }
    
    @Override
    public AjaxResult getDeviceKeys(String mac, Long userId) {
        if (StringUtils.isEmpty(mac)) {
            return AjaxResult.error("设备MAC地址不能为空");
        }
        
        if (userId == null) {
            return AjaxResult.error("用户ID不能为空");
        }
        
        // 根据MAC地址查询设备是否存在
        Map<String, Object> device = deviceMapper.selectDeviceByMac(mac);
        if (device == null || device.isEmpty()) {
            return AjaxResult.error("未找到指定MAC地址的设备");
        }
        
        // 构建查询条件
        ATenantkey query = new ATenantkey();
        query.setMac(mac);
        query.setTenantId(userId);
        query.setType("1");

        // 查询用户拥有的该设备的钥匙
        List<ATenantkey> keys = tenantkeyMapper.selectATenantkeyList(query);
        
        // 处理返回数据
        List<Map<String, Object>> resultList = new ArrayList<>();
        
        // 处理钥匙状态
        for (ATenantkey key : keys) {
            Map<String, Object> keyMap = new HashMap<>();
            // 复制对象属性到Map
            keyMap.put("id", key.getId());
            keyMap.put("mac", key.getMac());
            keyMap.put("tenantId", key.getTenantId());
            keyMap.put("homeId", key.getHomeId());
            keyMap.put("startTime", key.getStartTime());
            keyMap.put("endTime", key.getEndTime());
            keyMap.put("pwdId", key.getPwdId());
            keyMap.put("isItAvailable", key.getIsItAvailable());
            keyMap.put("password", key.getPassword());
            keyMap.put("cardNo", key.getCardNo());
            keyMap.put("type", key.getType());
            keyMap.put("status", key.getStatus());
            keyMap.put("uniCode", key.getUniCode());
            
            // 处理过期状态
            Date now = new Date();
            if (key.getStartTime() != null && key.getEndTime() != null) {
                if (now.after(key.getEndTime())) {
                    keyMap.put("expiryStatus", "已过期");
                } else if (now.before(key.getStartTime())) {
                    keyMap.put("expiryStatus", "未激活");
                } else {
                    keyMap.put("expiryStatus", "已激活");
                }
            } else {
                // 如果没有设置开始/结束时间，视为永久有效
                keyMap.put("expiryStatus", "已激活");
            }
            
            // 处理冻结状态
            if (key.getIsItAvailable() == 0) {
                keyMap.put("freezeStatus", "正常");
            } else {
                keyMap.put("freezeStatus", "已冻结");
            }
            
            resultList.add(keyMap);
        }
        
        return AjaxResult.success(resultList);
    }

    @Override
    public AjaxResult submitFaultReport(String waringType, String remark, String remark2, String img, Long userId, String mac, Long homeId) {
        if (StringUtils.isEmpty(remark)) {
            return AjaxResult.error("故障描述不能为空");
        }
        
        if (StringUtils.isEmpty(waringType)) {
            waringType = "1"; // 默认为故障上报类型
        }
        
        // 创建故障报告对象
        AWaringInfo waringInfo = new AWaringInfo();
        waringInfo.setWaringType(waringType);
        waringInfo.setRemark(remark);
        waringInfo.setImg(img);
        waringInfo.setState("0"); // 默认未处理状态
        waringInfo.setTenantId(userId.toString());
        waringInfo.setCreateTime(new Date());
        
        // 处理MAC地址和房间ID的关联
        if (!StringUtils.isEmpty(mac)) {
            // 如果提供了MAC地址，则直接使用
            waringInfo.setMac(mac);
            
            // 如果没有提供房间ID，则根据MAC地址查询
            if (homeId == null) {
                Map<String, Object> deviceInfo = deviceMapper.selectDeviceByMac(mac);
                if (deviceInfo != null && deviceInfo.containsKey("homeId")) {
                    String roomId = deviceInfo.get("homeId").toString();
                    waringInfo.setHomeId(roomId);
                }
            } else {
                // 如果同时提供了MAC和房间ID，则使用房间ID
                waringInfo.setHomeId(homeId.toString());
            }
        } else if (homeId != null) {
            // 如果只提供了房间ID，则根据房间ID查询MAC地址
            Map<String, Object> deviceInfo = deviceMapper.selectDeviceByHomeId(homeId);
            if (deviceInfo != null) {
                if (deviceInfo.containsKey("mac")) {
                    String deviceMac = deviceInfo.get("mac").toString();
                    waringInfo.setMac(deviceMac);
                }
                waringInfo.setHomeId(homeId.toString());
            }
        }
        
        // 插入记录
        int rows = waringInfoMapper.insertAWaringInfo(waringInfo);
        if (rows > 0) {
            return AjaxResult.success("故障上报成功");
        } else {
            return AjaxResult.error("故障上报失败");
        }
    }
    
    @Override
    public AjaxResult getFaultReportList(Long userId, Integer pageNum, Integer pageSize) {
        if (userId == null) {
            return AjaxResult.error("用户ID不能为空");
        }
        
        // 创建查询条件
        AWaringInfo query = new AWaringInfo();
        query.setTenantId(userId.toString());
        
        // 设置分页参数（如果有）
        if (pageNum != null && pageSize != null) {
            query.setPageNum(pageNum);
            query.setPageSize(pageSize);
        }
        
        // 查询用户的故障报告列表
        List<AWaringInfo> reportList = waringInfoMapper.selectAWaringInfoListApp(query);
        
        // 获取总记录数
        Integer total = waringInfoMapper.selectAWaringInfoListCount(query);
        
        // 构建返回结果
        Map<String, Object> result = new HashMap<>();
        result.put("rows", reportList);
        result.put("total", total);
        
        return AjaxResult.success(result);
    }
    
    @Override
    public AjaxResult getFaultReportDetail(Long id, Long userId) {
        if (id == null) {
            return AjaxResult.error("故障报告ID不能为空");
        }
        
        if (userId == null) {
            return AjaxResult.error("用户ID不能为空");
        }
        
        // 查询故障报告详情
        AWaringInfo report = waringInfoMapper.selectAWaringInfoById(id);
        
        // 验证是否存在
        if (report == null) {
            return AjaxResult.error("未找到指定的故障报告");
        }
        
        // 验证是否为当前用户的故障报告
        if (!userId.toString().equals(report.getTenantId())) {
            return AjaxResult.error("无权查看该故障报告");
        }
        
        return AjaxResult.success(report);
    }
    
    @Override
    public AjaxResult updateFaultReport(Long id, String waringType, String remark, String remark2, String img, Long userId) {
        if (id == null) {
            return AjaxResult.error("故障报告ID不能为空");
        }
        
        if (StringUtils.isEmpty(remark)) {
            return AjaxResult.error("故障描述不能为空");
        }
        
        if (userId == null) {
            return AjaxResult.error("用户ID不能为空");
        }
        
        // 查询原故障报告
        AWaringInfo report = waringInfoMapper.selectAWaringInfoById(id);
        
        // 验证是否存在
        if (report == null) {
            return AjaxResult.error("未找到指定的故障报告");
        }
        
        // 验证是否为当前用户的故障报告
        if (!userId.toString().equals(report.getTenantId())) {
            return AjaxResult.error("无权修改该故障报告");
        }
        
        // 验证是否已处理（已处理的报告不允许修改）
        if ("1".equals(report.getState())) {
            return AjaxResult.error("已处理的故障报告不允许修改");
        }
        
        // 更新故障报告信息
        report.setWaringType(waringType);
        report.setRemark(remark);

        // 只有在传入新图片时才更新
        if (!StringUtils.isEmpty(img)) {
            report.setImg(img);
        }
        
        report.setUpdateTime(new Date());
        
        // 更新记录
        int rows = waringInfoMapper.updateAWaringInfo(report);
        if (rows > 0) {
            return AjaxResult.success("故障报告修改成功");
        } else {
            return AjaxResult.error("故障报告修改失败");
        }
    }

    /**
     * 根据用户ID查询用户基本信息
     *
     * @param userId 用户ID
     * @return 用户基本信息
     */
    @Override
    public AjaxResult getUserInfoById(Long userId) {
        // 查询租户基本信息
        Map<String, Object> userInfo = new HashMap<>();

        // 从租户表查询用户信息
        ATenantuser tenant = tenantuserMapper.selectATenantuserById2(userId);

        // 如果租户不存在
        if (tenant == null) {
            return AjaxResult.error("租户不存在");
        }

        // 设置租户基本信息
        userInfo.put("userId", tenant.getId());
        userInfo.put("name", tenant.getName());
        userInfo.put("phone", tenant.getPhone());
        userInfo.put("homeId", tenant.getHomeId());
        userInfo.put("cellName", tenant.getCellName());
        userInfo.put("unitName", tenant.getUnitName());
        userInfo.put("floorName", tenant.getFloorName());
        userInfo.put("roomName", tenant.getRoomName());
        userInfo.put("type", tenant.getType());

        // 返回租户信息
        return AjaxResult.success(userInfo);
    }
    
    @Override
    public List<Map<String, Object>> getNotificationsByHomeId(Long homeId) {
        // 直接通过住宅ID查询小区公告
        List<Map<String, Object>> notifications = sysNoticeMapper.selectNotificationsByHomeId(homeId);
        
        if (notifications == null) {
            // 如果没有找到公告，返回空列表
            notifications = new ArrayList<>();
        }
        
        return notifications;
    }
    
    @Override
    public Map<String, Object> getNotificationDetail(String id) {
        // 查询公告详情
        Map<String, Object> detail = sysNoticeMapper.selectNotificationById(id);
        
        if (detail == null) {
            // 如果未找到公告详情，返回null
            return null;
        }
        
        return detail;
    }

    /**
     * 通过homeId获取打卡地点坐标信息
     *
     * @param homeId 房屋ID
     * @return 返回包含经纬度的Map
     */
    @Override
    public Map<String, Object> getCheckinLocationByHomeId(Long homeId) {
        Map<String, Object> result = new HashMap<>();
        
        // 通过homeId查询租户信息获取cellId
        ATenantuser queryParam = new ATenantuser();
        queryParam.setHomeId(homeId);
        List<ATenantuser> tenants = tenantuserMapper.selectATenantuserList(queryParam);
        if (tenants == null || tenants.isEmpty() || tenants.get(0).getCellId() == null) {
            return result;
        }
        
        // 通过cellId获取小区信息
        ACell cell = aCellMapper.selectACellById(tenants.get(0).getCellId());
        if (cell == null) {
            return result;
        }
        
        // 返回小区的经纬度信息
        result.put("latitude", cell.getLatitude());
        result.put("longitude", cell.getLongitude());
        result.put("address", cell.getAddress()); // 添加地址信息
        
        return result;
    }

    @Override
    public List<Map<String, Object>> getOpenLockRecords(Long homeId, String dateStr) {
        try {
            // 构建SQL查询语句
            StringBuilder sql = new StringBuilder();
            sql.append("SELECT ");
            sql.append("a.id, a.mac, a.logId, a.create_time, a.keyId, a.tenant_id, a.type, ");
            sql.append("tu.name AS username, tu.phone, ");
            sql.append("c.name AS cell_name, u.name AS unit_name, f.floor_name, h.roomName AS room_name ");
            sql.append("FROM a_openlock a ");
            sql.append("LEFT JOIN a_tenantuser tu ON a.tenant_id = tu.id ");
            sql.append("LEFT JOIN a_build_home h ON a.home_id = h.id ");
            sql.append("LEFT JOIN a_floor f ON h.floor_id = f.id ");
            sql.append("LEFT JOIN a_unit u ON f.unit_id = u.id ");
            sql.append("LEFT JOIN a_cell c ON u.cell_id = c.id ");
            sql.append("WHERE a.home_id = ? ");
            
            List<Object> params = new ArrayList<>();
            params.add(homeId);
            
            // 如果指定了日期，添加日期条件
            if (dateStr != null && !dateStr.isEmpty()) {
                sql.append("AND DATE(a.create_time) = ? ");
                params.add(dateStr);
            }
            
            sql.append("ORDER BY a.create_time DESC");
            
            // 执行查询
            List<Map<String, Object>> records = jdbcTemplate.queryForList(sql.toString(), params.toArray());
            
            return records;
        } catch (Exception e) {
            e.printStackTrace();
            return new ArrayList<>();
        }
    }

    /**
     * 检查手机号是否已注册
     */
    private boolean isPhoneRegistered(String phoneNumber) {
        if (StringUtils.isEmpty(phoneNumber)) {
            return false;
        }
        ATenantuser user = tenantuserMapper.selectATenantuserByPhone(phoneNumber);
        return user != null;
    }

    @Override
    public boolean sendVerificationCode(String phoneNumber) {
        try {
            // 1. 检查手机号是否已注册
            if (!isPhoneRegistered(phoneNumber)) {
                throw new ServiceException("该手机号未注册");
            }

            // 2. 检查用户状态
            ATenantuser user = tenantuserMapper.selectATenantuserByPhone(phoneNumber);
            if (user == null) {
                throw new ServiceException("用户不存在");
            }
            if (user.getIsFlag() == "2") {
                throw new ServiceException("账号已退租");
            }

            // 3. 生成6位随机验证码
            String code = String.format("%06d", (int) (Math.random() * 1000000));

            // 4. 将验证码存入Redis，设置过期时间为5分钟
            String key = SMS_CODE_KEY_PREFIX + phoneNumber;
            redisCache.setCacheObject(key, code, CODE_EXPIRE_MINUTES, TimeUnit.MINUTES);

            // 5. 发送验证码短信
            boolean success = iSmsService.sendVerificationCode(phoneNumber, code);
            if (!success) {
                throw new ServiceException("验证码发送失败");
            }

            log.info("验证码发送成功，手机号: {}", phoneNumber);
            return true;
        } catch (Exception e) {
            log.error("发送验证码失败: {}", e.getMessage());
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public boolean verifyCode(String phoneNumber, String code) {
        try {
            // 1. 从Redis获取验证码
            String key = SMS_CODE_KEY_PREFIX + phoneNumber;
            String savedCode = redisCache.getCacheObject(key);
            
            // 2. 验证码不存在或已过期
            if (savedCode == null) {
                log.error("验证码不存在或已过期: {}", phoneNumber);
                return false;
            }
            
            // 3. 验证码不匹配
            if (!savedCode.equals(code)) {
                log.error("验证码不匹配: {}", phoneNumber);
                return false;
            }
            
            // 4. 验证通过，删除验证码
            redisCache.deleteObject(key);
            log.info("验证码验证通过: {}", phoneNumber);
            return true;
        } catch (Exception e) {
            log.error("验证码验证失败: {}", phoneNumber, e);
            return false;
        }
    }
} 